package com.younion.security;

import java.util.Arrays;
import java.util.List;

import org.apache.log4j.Logger;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.SimplePrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;

import com.google.common.collect.Lists;
import com.younion.business.IPermissionsService;
import com.younion.business.IRolesService;
import com.younion.business.IUserService;
import com.younion.permission.NodePermission;
import com.younion.permission.PermissionUtil;
import com.younion.vo.PermissionsVO;
import com.younion.vo.RolesVO;
import com.younion.vo.UserVO;

public class UserManagerRealm extends AuthorizingRealm {

    private static Logger    logger = Logger.getLogger(UserManagerRealm.class);

    private IUserService userService;
    
    private IRolesService rolesService;
    @Autowired
    private IPermissionsService permissionsService;
    

    public UserManagerRealm() {
        //setCredentialsMatcher(new HashedCredentialsMatcher(Md5Hash.ALGORITHM_NAME));
        // setCredentialsMatcher(new SimpleCredentialsMatcher());
    }
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
    	CaptchaUsernamePasswordToken token = (CaptchaUsernamePasswordToken) authcToken;
        if (token != null) {
            return new SimpleAuthenticationInfo( token.getUsername(), token.getPassword(), getName());
        }
        
        return null;
    }

    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String account = (String) principals.fromRealm(getName()).iterator().next();
        UserVO user = null;
		try {
			user = userService.getByUser(new UserVO(account));
			if (user != null) {
	            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
	            RolesVO role = rolesService.getById(user.getRole().toString());
	            info.addRole(NodePermission.R.getName() + PermissionUtil.colon + role.getRoleType() + PermissionUtil.colon + user.getRole());
	            List<PermissionsVO> permissions = permissionsService.selectByIds(Arrays.asList(role.getPermissions().split(PermissionUtil.comma)));
	            if (!CollectionUtils.isEmpty(permissions)) {
	            	List<String> strPermissions = Lists.newArrayList();
	                for (PermissionsVO p : permissions) {
	                    strPermissions.add(p.getCode().trim());
	                    info.addRole(p.getCode().trim());
	                }
	                info.addStringPermissions(strPermissions);
	            }
	            return info;
	        }
		} catch (Exception e) {
			return null;
		}

        return null;
    }

    /**
     * Clear the subject's cache in shiro.
     */
    public void clearCurrentSubjectInfoInCache() {
        clearCachedAuthorizationInfo(SecurityUtils.getSubject().getPrincipals());
    }

    /**
     * Clear subject info in cache by user
     * 
     * @param userName
     */
    public void clearSubjectInfoInCache(String userName) {
        SimplePrincipalCollection principals = new SimplePrincipalCollection(userName, getName());
        clearCachedAuthorizationInfo(principals);
    }

    /**
     * Clear all subjects cache in shiro.
     */
    public void clearAllSubjectInfoInCache() {
        Cache<Object, AuthorizationInfo> cache = getAuthorizationCache();
        if (cache != null) {
            for (Object key : cache.keys()) {
                cache.remove(key);
            }
        }
    }

	public IUserService getUserService() {
		return userService;
	}

	public void setUserService(IUserService userService) {
		this.userService = userService;
	}

	public IRolesService getRolesService() {
		return rolesService;
	}

	public void setRolesService(IRolesService rolesService) {
		this.rolesService = rolesService;
	}

	public IPermissionsService getPermissionsService() {
		return permissionsService;
	}

	public void setPermissionsService(IPermissionsService permissionsService) {
		this.permissionsService = permissionsService;
	}


}
